
// ToolsLib Project

/* ToolsLib library for RusRoute firewall and other projects of
 * Andrey A. Moiseenko / IE Moiseenko A.A. (Russia)
 * e-mail: support@maasoftware.ru, maa2002@mail.ru
 * web: http://maasoftware.ru, http://maasoftware.com, http://maasoft.ru, http://maasoft.org
 * Author's full name: Andrey Alekseevitch Moiseenko
 * (russian name: Моисеенко Андрей Алексеевич)
 */

// ToolsLib/MaaXml.h

/* Copyright (C) 2002-2024 Andrey A. Moiseenko (support@maasoftware.ru)
 * All rights reserved.
 *
 * This library contains cross-platform classes for working with
 * xml format using pimpl model from Herb Sutter "Exceptional C++"
 * (Герб Саттер "Решение сложных задач на С++"). First dated 18.11.2006.
 * The library implementation written
 * by Andrey A. Moiseenko (support@maasoftware.ru).
 * This library and applications are
 * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
 * as long as the following conditions are aheared to.
 *
 * Copyright remains Andrey A. Moiseenko, and as such any Copyright notices in
 * the code are not to be removed.  If this code is used in a product,
 * Andrey A. Moiseenko should be given attribution as the author of the parts used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by Andrey A. Moiseenko (support@maasoftware.ru)
 *
 * THIS SOFTWARE IS PROVIDED BY ANDREY A. MOISEENKO ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */

#ifndef __TOOLS_MAAXML_H
#define __TOOLS_MAAXML_H

#define CMaa_JSON_HEX_QUOT  0x01
#define CMaa_JSON_HEX_TAG   0x02
#define CMaa_JSON_HEX_AMP   0x04
#define CMaa_JSON_HEX_APOS  0x08

CMaaString StrToJson(CMaaString x, int MaxLen = 0x7fffffff, int Flags = 0);
int JsonCharLen(const char* p, int i, int MaxLen, bool bWeak = true) noexcept;
CMaaString JsonToStr(CMaaString x);

//extern void * gV;
//-------------------------------------------------------------------------------------------------
class CMaaXmlDocument;
class CMaaXmlProcessingInstruction;
class CMaaXmlElement;
class CMaaXmlNode;
class CMaaXmlNodeImpl;
//-------------------------------------------------------------------------------------------------
typedef CMaaXmlNodeImpl* CMaaXmlHandle;
//-------------------------------------------------------------------------------------------------
class CMaaXmlNode
{
    friend class CMaaXmlNodeImpl;
    friend class CMaaXmlDocument;
    //CMaaRefDLink<CMaaXmlNodeImpl> m_Imp;
    CMaaXmlNodeImpl * m_Imp;
protected:
    bool AddNode(CMaaXmlNode &Node);
    bool RemNode(CMaaXmlNode &Node);
public:
    bool AddAttribute(const CMaaString &Name, const CMaaString &Value);
    template <int N> bool AddAttribute(const char (&Name)[N], const CMaaString &Value)
    {
        return AddAttribute(Name[N - 1] ? CMaaString(Name, N, CMaaString::eROMemString) : CMaaString(Name, N - 1, CMaaString::eROMemString0), Value);
    }
    template <int N> bool AddAttribute(const CMaaString &Name, const char (&Value)[N])
    {
        return AddAttribute(Name, Value[N - 1] ? CMaaString(Value, N, CMaaString::eROMemString) : CMaaString(Value, N - 1, CMaaString::eROMemString0));
    }
    template <int N> bool AddAttribute(char (&Name)[N], const CMaaString &Value) = delete;
    template <int N> bool AddAttribute(const CMaaString &Name, char (&Value)[N]) = delete;
    template <int N1, int N2> bool AddAttribute(const char (&Name)[N1], const char (&Value)[N2])
    {
            return AddAttribute(
                Name[N1 - 1] ? CMaaString(Name, N1, CMaaString::eROMemString) : CMaaString(Name, N1 - 1, CMaaString::eROMemString0),
                Value[N2 - 1] ? CMaaString(Value, N2, CMaaString::eROMemString) : CMaaString(Value, N2 - 1, CMaaString::eROMemString0)
                );
    }
    template <int N1, int N2> bool AddAttribute(char (&Name)[N1], const char (&Value)[N2]) = delete;
    template <int N1, int N2> bool AddAttribute(const char (&Name)[N1], char (&Value)[N2]) = delete;
    template <int N1, int N2> bool AddAttribute(char (&Name)[N1], char (&Value)[N2]) = delete;
    
    bool AddAttributeVerifyName(const CMaaString &Name, const CMaaString &Value);
    bool RemoveAttribute(const CMaaString &Name) noexcept;
    bool RemoveAttribute(const char * pszName) noexcept;
    int RemoveAllAttributes() noexcept; // returns number of attributes that was removed
    bool AddString(const CMaaString &Name, const CMaaString &Value);
    bool RemoveString(const CMaaString &Name) noexcept;
    bool RemoveString(const char * pszName) noexcept;
    int RemoveAllStrings() noexcept; // returns number of attributes that was removed
    int CopyAttributes(const CMaaXmlNode From, bool bHiddenPtrs = false);
    bool SetString(CMaaString Value) noexcept;
    const CMaaString& GetString(bool *pIsFound = nullptr) const noexcept;
public:
    CMaaXmlNode(CMaaXmlNodeImpl* I) noexcept;
    CMaaXmlNode(int Type, const CMaaString &Name);
    CMaaXmlNode(const CMaaXmlNode& That) noexcept;
    CMaaXmlNode(CMaaXmlNode&& That) noexcept;
    CMaaXmlNode& operator=(const CMaaXmlNode& That) noexcept;
    CMaaXmlNode& operator=(CMaaXmlNode&& That) noexcept;
    virtual ~CMaaXmlNode();
    CMaaXmlHandle GetHandle() const noexcept;
    //operator CMaaXmlHandle ();
    CMaaXmlNode GetParent() noexcept;
    operator bool() const noexcept
    {
        return !IsNull();
    }
    CMaaXmlNode operator++() noexcept
    {
        return (*this = FindNext());
    }
    CMaaXmlNode operator--() noexcept
    {
        return (*this = FindPrev());
    }
    bool IsProcessingInstruction() const noexcept;
    bool IsElement() const noexcept;
    CMaaXmlNode FirstChild() const noexcept;
    CMaaXmlNode NextSibling() const noexcept;
    CMaaXmlNode PrevSibling() const noexcept;
    bool IsNull() const noexcept
    {
        return !m_Imp;
    }
    bool IsValid() noexcept
    {
        return !IsNull();
    }
    bool IsString() const noexcept
    {
        return GetString().IsNotEmpty();
    }
    bool AddProcessingInstruction(CMaaXmlNode & Node);
    bool AppendChild(CMaaXmlNode & Node);
    bool RemoveChild(CMaaXmlNode & Node); // Detach child from parent(this)
    bool Remove(); // Detach child from parent(this)
    static CMaaString EncodeAttr(const CMaaString &s, int iFeatures = 0);
    static void EncodeAttr(CMaaConcatString &c, const CMaaString &s, int iFeatures = 0);
    static CMaaString DecodeAttr(const CMaaString &s, int cp /*= e_utf8*/, CMaaStringsContinedBuffer * pContBuf = nullptr);
    static CMaaString EncodeString(const CMaaString &s, int iFeatures = 0, const CMaaString &Name = CMaaStringZ); // {return ((iFeatures & CMaaXmlDocument::eRssCDataStrings) && Name != "lastBuildDate") ? CMaaString("<![CDATA[") + s + "]]>" : EncodeAttr(s, iFeatures);}
    static void EncodeString(CMaaConcatString &c, const CMaaString &s, int iFeatures, const CMaaString &Name = CMaaStringZ); // chk for Rss {return EncodeAttr(c, s, iFeatures);}
    static CMaaString DecodeString(CMaaString s, int cp /*= e_utf8*/) {return DecodeAttr(s, cp);}
    CMaaString ToString(const CMaaString &Sp0 = CMaaStringZ, const CMaaString &DeltaSp = CMaaStringSp, const CMaaString &EndOfLine = CMaaStringLf, int iFeatures = 0) const;
    void ToString(CMaaConcatString& s, const CMaaString& Sp0 = CMaaStringZ, const CMaaString& DeltaSp = CMaaStringSp, const CMaaString& EndOfLine = CMaaStringLf, int iFeatures = 0) const;
    void ToJson(CMaaConcatString& s, const CMaaString& Sp0 = CMaaStringZ, const CMaaString& DeltaSp = CMaaStringSp, const CMaaString& EndOfLine = CMaaStringLf, int Flags = 0 /*CMaa_JSON_HEX_APOS | ...*/, int MaxNameLen = 128, int MaxAttrLen = 128) const;
    //CMaaXmlProcessingInstruction toProcessingInstruction();
    //CMaaXmlElement toElement();
    const CMaaString& GetName() const noexcept;
    void ChangeName(const CMaaString &Name);
    const CMaaString& FindAttribute(const CMaaString &Name, bool *pIsFound = nullptr) const noexcept;
    const CMaaString& FindAttribute(const char * pszName, bool *pIsFound = nullptr) const noexcept; // noexcept
    const CMaaString& FindString(const CMaaString &Name, bool *pIsFound = nullptr) const noexcept;
    const CMaaString& FindString(const char * pszName, bool *pIsFound = nullptr) const noexcept; // noexcept
    const void * FirstStringIterator() const noexcept;
    const void * FirstAttributeIterator() const noexcept;
    bool GetString(const void * Iterator, CMaaString *pName, CMaaString *pValue) const noexcept;
    bool GetAttribute(const void * Iterator, CMaaString *pName, CMaaString *pValue) const noexcept;
    const void * NextStringIterator(const void * Iterator) const noexcept;
    const void * NextAttributeIterator(const void * Iterator) const noexcept;
    CMaaXmlNode FindNode(const CMaaString &Name, int *pN = nullptr) const noexcept;
    CMaaXmlNode FindNode(const char * pszName, int *pN = nullptr) const noexcept; // noexcept
    CMaaXmlNode FindNext() const noexcept;
    CMaaXmlNode FindPrev() const noexcept;
    CMaaXmlNode FindNodeWithAttr(const CMaaString& Name, const CMaaString& AttrName, const CMaaString &AttrVal, CMaaXmlNode SkipNode = CMaaXmlNode(nullptr)) const noexcept;
    CMaaXmlNode FindNodeWithAttr(const CMaaString& Name, const char * pszAttrName, const CMaaString &AttrVal, CMaaXmlNode SkipNode = CMaaXmlNode(nullptr)) const noexcept;
    CMaaXmlNode FindNodeWithAttr(const char* pszName, const CMaaString& AttrName, const CMaaString &AttrVal, CMaaXmlNode SkipNode = CMaaXmlNode(nullptr)) const noexcept;
    CMaaXmlNode FindNodeWithAttr(const char* pszName, const char* pszAttrName, const CMaaString &AttrVal, CMaaXmlNode SkipNode = CMaaXmlNode(nullptr)) const noexcept;
    // Flags: 1 - cleanup cache, 2 - don't add to cache
    CMaaXmlNode FindNodeWithAttrRO(/*CMaaMutex * mtx,*/ const CMaaString& Name, const CMaaString& AttrName, const CMaaString &AttrVal, CMaaXmlNode SkipNode = CMaaXmlNode(nullptr), int Flags = 0) const; // for RO xml docs. Flags: 1 - cleanup cache, 2 - no negative cache storing
    CMaaXmlNode FindNodeWithAttrRO(/*CMaaMutex * mtx,*/ const CMaaString& Name, const char * pszAttrName, const CMaaString &AttrVal, CMaaXmlNode SkipNode = CMaaXmlNode(nullptr), int Flags = 0) const; // for RO xml docs. Flags: 1 - cleanup cache, 2 - no negative cache storing
    CMaaXmlNode FindNodeWithAttrRO(/*CMaaMutex * mtx,*/ const char* pszName, const CMaaString& AttrName, const CMaaString &AttrVal, CMaaXmlNode SkipNode = CMaaXmlNode(nullptr), int Flags = 0) const; // for RO xml docs. Flags: 1 - cleanup cache, 2 - no negative cache storing
    CMaaXmlNode FindNodeWithAttrRO(/*CMaaMutex * mtx,*/ const char* pszName, const char* pszAttrName, const CMaaString &AttrVal, CMaaXmlNode SkipNode = CMaaXmlNode(nullptr), int Flags = 0) const; // for RO xml docs. Flags: 1 - cleanup cache, 2 - no negative cache storing
    CMaaXmlNode FindNodeWithString(const CMaaString &Name, const CMaaString &StringName, const CMaaString &StringVal, CMaaXmlNode SkipNode = CMaaXmlNode(nullptr)) const noexcept;
    int ChangeNodesAttr(const CMaaString &Name, const CMaaString &AttrName, const CMaaString &OldVal, const CMaaString &NewVal);
    int RemoveNodesAttr(const CMaaString &Name, const CMaaString &AttrName, const CMaaString &Val) noexcept;
    int RemoveNodesWithAttr(const CMaaString &Name, const CMaaString &AttrName, const CMaaString &Val);
    int ChangeNodesString(const CMaaString &Name, const CMaaString &AttrName, const CMaaString &OldVal, const CMaaString &NewVal);
    int RemoveNodesString(const CMaaString &Name, const CMaaString &AttrName, const CMaaString &Val) noexcept;
    int RemoveNodesWithString(const CMaaString &Name, const CMaaString &AttrName, const CMaaString &Val);

    int AddHiddenPtr(const CMaaString &Name, void* ptr, void (*deref)(CMaaString, void*, void*) = nullptr, void* obj = nullptr, bool bDerefOld = true);
    int AddHiddenInt(const CMaaString &Name, int x); // Hidden ptrs and ints are mixed in the same scope
    int AddHiddenString(const CMaaString &Name, const CMaaString &Str);
    int RemoveHiddenPtr(const CMaaString &Name, bool bDeref = false);
    int RemoveHiddenInt(const CMaaString &Name, bool bDeref = false)
    {
        // Hidden ptrs and strings and ints are mixed in the same scope
        return RemoveHiddenPtr(Name, bDeref);
    }
    int RemoveHiddenString(const CMaaString &Name)
    {
        // Hidden string ptrs and ptrs and ints are mixed in the same scope
        return RemoveHiddenPtr(Name, true);
    }
    void* GetHiddenPtr(const CMaaString &Name, bool* bGot = nullptr) const noexcept;
    template <int N> void* GetHiddenPtr(const char (&pszName)[N], bool* bGot = nullptr) const noexcept
    {
        return GetHiddenPtr(pszName[N - 1] ? CMaaString(pszName, N, CMaaString::eROMemString) : CMaaString(pszName, N - 1, CMaaString::eROMemString0), bGot);
    }
    const CMaaString& GetHiddenString(const CMaaString &Name, bool* bGot = nullptr) const noexcept;
    template <int N> const CMaaString& GetHiddenString(const char (&pszName)[N], bool* bGot = nullptr) const noexcept
    {
        return GetHiddenString(pszName[N - 1] ? CMaaString(pszName, N, CMaaString::eROMemString) : CMaaString(pszName, N - 1, CMaaString::eROMemString0), bGot);
    }
    int GetHiddenInt(const CMaaString &Name, int Default = 0, bool *bGot = nullptr) const noexcept; // Hidden ptrs and ints are mixed in the same scope
    template <int N> int GetHiddenInt(const char (&pszName)[N], int Default = 0, bool *bGot = nullptr) const noexcept // Hidden ptrs and ints are mixed in the same scope
    {
        return GetHiddenInt(pszName[N - 1] ? CMaaString(pszName, N, CMaaString::eROMemString) : CMaaString(pszName, N - 1, CMaaString::eROMemString0), Default, bGot);
    }
    int RemoveAllHiddenPtrs(bool bDeref = false);
    int RemoveAllHiddenInts(bool bDeref = false)
    {
        // Hidden ptrs and ints are mixed in the same scope
        return RemoveAllHiddenPtrs(bDeref);
    }

    template <int N> int AddHiddenPtr(const char (&Name)[N], void* ptr, void (*deref)(CMaaString, void*, void*) = nullptr, void* obj = nullptr, bool bDerefOld = true)
    {
        return AddHiddenPtr(Name[N - 1] ? CMaaString(Name, N, CMaaString::eROMemString) : CMaaString(Name, N - 1, CMaaString::eROMemString0), ptr, deref, obj, bDerefOld);
    }
    template <int N> int AddHiddenInt(const char (&Name)[N], int x) // Hidden ptrs and ints are mixed in the same scope
    {
        return AddHiddenInt(Name[N - 1] ? CMaaString(Name, N, CMaaString::eROMemString) : CMaaString(Name, N - 1, CMaaString::eROMemString0), x);
    }
    template <int N> int AddHiddenString(const char (&Name)[N], const CMaaString &Str)
    {
        return AddHiddenString(Name[N - 1] ? CMaaString(Name, N, CMaaString::eROMemString) : CMaaString(Name, N - 1, CMaaString::eROMemString0), Str);
    }
    template <int N> int RemoveHiddenPtr(const char (&Name)[N], bool bDeref = false)
    {
        return RemoveHiddenPtr(Name[N - 1] ? CMaaString(Name, N, CMaaString::eROMemString) : CMaaString(Name, N - 1, CMaaString::eROMemString0), bDeref);
    }
    template <int N> int RemoveHiddenInt(const char (&Name)[N], bool bDeref = false)
    {
        // Hidden ptrs and strings and ints are mixed in the same scope
        return RemoveHiddenPtr(Name[N - 1] ? CMaaString(Name, N, CMaaString::eROMemString) : CMaaString(Name, N - 1, CMaaString::eROMemString0), bDeref);
    }
    template <int N> int RemoveHiddenString(const char (&Name)[N])
    {
        // Hidden string ptrs and ptrs and ints are mixed in the same scope
        return RemoveHiddenPtr(Name[N - 1] ? CMaaString(Name, N, CMaaString::eROMemString) : CMaaString(Name, N - 1, CMaaString::eROMemString0), true);
    }

    //template <int N> int c_tst(char (&txt)[N]);
    template <int N> int AddHiddenPtr(char (&Name)[N], void* ptr, void (*deref)(CMaaString, void*, void*) = nullptr, void* obj = nullptr, bool bDerefOld = true) = delete;
    template <int N> int AddHiddenInt(char (&Name)[N], int x) = delete; // Hidden ptrs and ints are mixed in the same scope
    template <int N> int AddHiddenString(char (&Name)[N], CMaaString Str) = delete;
    template <int N> int RemoveHiddenPtr(char (&Name)[N], bool bDeref = false) = delete;
    template <int N> int RemoveHiddenInt(char (&Name)[N], bool bDeref = false) = delete;
    template <int N> int RemoveHiddenString(char (&Name)[N]) = delete;
    template <int N> void* GetHiddenPtr(char (&pszName)[N], bool* bGot = nullptr) const noexcept = delete;
    template <int N> const CMaaString& GetHiddenString(char (&pszName)[N], bool* bGot = nullptr) const noexcept = delete;
    template <int N> void* GetHiddenInt(char (&pszName)[N], int Default = 0, bool* bGot = nullptr) const noexcept = delete;

    bool MoveUp();
    bool MoveDown();
    bool InsertBefore(CMaaXmlNode p); // in: *this is free, out: this will be before 'p'
    bool InsertAfter(CMaaXmlNode p); // in: *this is free, out: this will be after 'p'
    CMaaXmlNode CopyNode(CMaaXmlDocument &doc, bool bChilds = true, bool bHiddenPtrs = false/*not implemented*/) const;
    void ConvertToUtf8(bool bChilds = true, _dword cp =
#ifdef _WIN32
         CP_ACP
#else
         0
#endif
         );
    typedef void (* EnumAttributesFn)(CMaaString AttrName, CMaaString AttrValue, CMaaXmlNode &Node, void *Param);
    typedef void (* EnumStringsFn)(CMaaString AttrName, CMaaString AttrValue, CMaaXmlNode &Node, void *Param);

    class XX
    {
        CMaaXmlNodeImpl * m_Impl;
    protected:
        /*
          CMaaXmlNodeImpl& Impl() const
          {
               return *m_Impl;
          }
          */
    public:
        CMaaXmlNode n() const noexcept
        {
            return m_Impl;
        }
        CMaaString szTxt;
        bool bConst;

        XX(CMaaXmlNode &x, const CMaaString &Txt) noexcept;
        XX(const CMaaXmlNode &x, const CMaaString &Txt) noexcept;
        XX(const XX &That) noexcept;
        ~XX() noexcept;
        operator CMaaString() const noexcept;
        const CMaaString &crString() const noexcept;
        //operator const char * () const;
        operator const CMaaXmlNode() const noexcept;
        operator CMaaXmlNode() noexcept;
        bool operator=(const CMaaString &txt);
        bool operator=(const XX & That);
        bool operator==(const CMaaString &s) const noexcept
        {
            //return CMaaString(*this) == s;
            return crString() == s;
        }
        bool operator!=(const CMaaString &s) const noexcept
        {
            //return CMaaString(*this) != s;
            return crString() != s;
        }
        CMaaString operator+(const CMaaString &s) const
        {
            //return CMaaString(*this) + s;
            return crString() + s;
        }
    };

    XX operator[](const CMaaString &txt) noexcept
    {
        return XX(*this, txt);
    }

    template <int N> XX operator[](char (&pszText)[N]) = delete;
    template <int N> XX operator[](const char (&pszText)[N]) noexcept
    {
        return XX(*this, pszText[N - 1] ? CMaaString(pszText, N, CMaaString::eROMemString) : CMaaString(pszText, N - 1, CMaaString::eROMemString0));
    }

    XX operator[](const CMaaString &txt) const noexcept
    {
        return XX(*this, txt);
    }

    template <int N> XX operator[](char (&pszText)[N]) const = delete;
    template <int N> XX operator[](const char (&pszText)[N]) const noexcept
    {
        return XX(*this, pszText[N - 1] ? CMaaString(pszText, N, CMaaString::eROMemString) : CMaaString(pszText, N - 1, CMaaString::eROMemString0));
    }

    bool operator<<(CMaaXmlNode &x)
    {
        return AppendChild(x);
    }
protected:
    static void stEnumAttrFn(CMaaString AttrName, CMaaString AttrValue, void *Param);
public:
    int EnumAttributes(EnumAttributesFn Fn, void * Param = nullptr);
    int EnumStrings(EnumStringsFn Fn, void * Param = nullptr);
    int SortAttributes() noexcept;
    int SortStrings() noexcept;
    enum
    {
        eAttributes = 0x01,
        eStrings = 0x02,
        eRecursive = 0x100,
        eAll = eAttributes | eStrings,
        eAllRecursive = eAll | eRecursive
    };
    void Sort(int Flags = eAllRecursive) noexcept;

    int GetRefCount() const noexcept;
protected:
    bool AddBefore(CMaaXmlNode n);
    bool AddAfter(CMaaXmlNode n);
};
//-------------------------------------------------------------------------------------------------
class CMaaXmlProcessingInstruction : public CMaaXmlNode
{
public:
    CMaaXmlProcessingInstruction(const CMaaString &Name);
    CMaaXmlProcessingInstruction(CMaaXmlNode &Node) noexcept;
    enum
    {
        eVersion = 1,
        eEncoding
    };
    bool AddInstruction(int Type, CMaaString Value = CMaaStringZ);
    bool AddInstruction(const CMaaString &Name, const CMaaString &Value);
};
//-------------------------------------------------------------------------------------------------
class CMaaXmlElement : public CMaaXmlNode
{
public:
    CMaaXmlElement(const CMaaString &Name);
    CMaaXmlElement(CMaaXmlNode &Node) noexcept;
    bool SetAttribute(const CMaaString &Name, const CMaaString &Value);
    bool AppendChild(CMaaXmlNode &Node);
};
//-------------------------------------------------------------------------------------------------
class CMaaXmlDocument
{
    CMaaString m_Name;
    CMaaXmlNode m_Root;
public:
    static int s_PaddingBytes;
    enum
    {
        eAcceptStrings = 0x01,
        eTreatEmptyNodeAsAString = 0x03,
        eComplexStrings = 0x04,
        // all strings are nodes
        eRssCDataStrings = 0x08,
        // use <![CDATA[text]]> for strings except <lastBuildDate>
        eCachedNames = 0x10,
        eCachedValues = 0x20,
        eCachedStrings = 0x40,
        eContinedBuffer = 0x80,
        eCachedRONames = 0x100,
        eCachedROValues = 0x200,
        eCachedROStrings = 0x400,
        eCachedAll = eCachedNames | eCachedValues | eCachedStrings,
        eCachedROAll = eCachedRONames | eCachedROValues | eCachedROStrings,
        eCachedOpts = eCachedNames,
        eCrLfAreInTheSimplePresentation = 0x100,
        eDoNotAddDoctypeKey = 0x200,
        eDefault9 = eTreatEmptyNodeAsAString * 0 | eAcceptStrings | eCachedOpts | eComplexStrings * 0 | eRssCDataStrings * 0 | eContinedBuffer,
        eDefault1 = eAcceptStrings | eCachedOpts,
        eDefault1WithRO = eDefault1 | eCachedROAll,
        eDefaultRO = eAcceptStrings | eCachedROAll,
        eDefault2 = eAcceptStrings | eContinedBuffer,
        eDefault = eAcceptStrings | eCachedOpts * 0 | eContinedBuffer
    };
    CMaaXmlDocument(const CMaaString &Name = CMaaStringDoc);
    CMaaXmlDocument(const CMaaString &Name, const CMaaString &RootName);
    CMaaXmlDocument(CMaaXmlDocument & That, bool bCopy = false);
    ~CMaaXmlDocument();
    CMaaXmlProcessingInstruction CreateProcessingInstruction(CMaaString xml = "xml");
    CMaaXmlElement CreateElement(const CMaaString &Name);
    template <int N> CMaaXmlElement CreateElement(char (&Name)[N]) = delete;
    template <int N> CMaaXmlElement CreateElement(const char (&Name)[N])
    {
        return CreateElement(Name[N - 1] ? CMaaString(Name, N, CMaaString::eROMemString) : CMaaString(Name, N - 1, CMaaString::eROMemString0));
    }
    bool AddProcessingInstruction(CMaaXmlNode &Node);
    void AppendChild(CMaaXmlNode &Node);
    //bool SetContent(CMaaFile File, CMaaString *errorMsg, int *errorLine, int *errorColumn);
    bool SetContent(CMaaString Text, CMaaString *errorMsg = nullptr, int *errorLine = nullptr, int *errorColumn = nullptr, int iFeatures = eDefault);
    bool SetContent(CMaaString Text, const CMaaUnivHash<CMaaString, CMaaString>& hStringsCache, CMaaString* errorMsg = nullptr, int* errorLine = nullptr, int* errorColumn = nullptr, int iFeatures = eDefaultRO);
    bool SetContent(CMaaString Text, CMaaUnivHash<CMaaString, CMaaString> & hStringsCache, CMaaString* errorMsg = nullptr, int* errorLine = nullptr, int* errorColumn = nullptr, int iFeatures = eDefault);
    bool SetJson(const CMaaString &Text, CMaaString* errorMsg = nullptr, int* errorLine = nullptr, int* errorColumn = nullptr);
    CMaaXmlNode FirstChild() const noexcept;
    CMaaXmlElement DocumentElement() const noexcept;
    CMaaString ToString(int ApproxLength = -1, CMaaString Sp0 = CMaaStringZ, CMaaString DeltaSp = CMaaStringSp, CMaaString EndOfLine = CMaaStringLf, int iFeatures = 0 /*eCrLfAreInTheSimplePresentation|eDoNotAddDoctypeKey|eRssCDataStrings*/) const;
    CMaaString ToString(CMaaString Sp0, CMaaString DeltaSp = CMaaStringSp, CMaaString EndOfLine = CMaaStringLf, int iFeatures = 0) const;
    CMaaString ToJson(int ApproxLength = -1, CMaaString Sp0 = CMaaStringZ, CMaaString DeltaSp = CMaaStringSpSp, CMaaString EndOfLine = CMaaStringLf, int Flags = 0 /*CMaa_JSON_HEX_APOS | ...*/, int MaxNameLen = 128, int MaxAttrLen = 128) const;
    CMaaXmlDocument & operator=(const CMaaXmlDocument & That) noexcept;
    bool LoadFromFile(const CMaaString &FileName, bool bThrow = true, CMaaString *errorMsg = nullptr, int *errorLine = nullptr, int *errorColumn = nullptr, int iFeatures = eTreatEmptyNodeAsAString * 0 + eAcceptStrings + eCachedOpts);
    bool SaveToFile(const CMaaString &FileName, bool bThrow = true, CMaaString Sp0 = CMaaStringZ, CMaaString DeltaSp = CMaaStringSp, CMaaString EndOfLine = CMaaStringCrLf, int iFeatures = 0 /*eCrLfAreInTheSimplePresentation|eDoNotAddDoctypeKey|eRssCDataStrings*/) const;
    void AddReplaceProcessingInstruction(CMaaString Encoding = "utf-8", CMaaString Version = "1.0", _dword ToUtf8Cp = -1); // -2 - не перекодировать строки
    void ConvertToUtf8(_dword cp = -1); // CP_ACP /*0*/ / 1251
};
//-------------------------------------------------------------------------------------------------

#endif // __TOOLS_MAAXML_H
